package com.bckj.freshnow.common.gen;

import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericToStringSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;

import java.util.concurrent.TimeUnit;


/**
 * 发号器
 */
@Slf4j
@Component
public class IdGenerator implements ApplicationContextAware {

    private static RedisTemplate<String, Long> stringLongRedisTemplate;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        RedisConnectionFactory connectionFactory = applicationContext.getBean(RedisConnectionFactory.class);
        stringLongRedisTemplate = new RedisTemplate<>();
        stringLongRedisTemplate.setKeySerializer(RedisSerializer.string());
        stringLongRedisTemplate.setValueSerializer(new GenericToStringSerializer<>(Long.class));
        stringLongRedisTemplate.setExposeConnection(true);
        stringLongRedisTemplate.setConnectionFactory(connectionFactory);
        stringLongRedisTemplate.afterPropertiesSet();
    }

    /**
     * 生成订单号（4位店铺id4位用户id+6位日期字符串+6位自增数）
     * 使用redis 时间误差不能超过5分钟
     * 支持一秒内1000000并发
     */
    public static String generateOrderNo(String prefix) {
        long i = RandomUtil.randomInt(1000000);
        String noStr;
        String nowStr = StrUtil.toString(System.currentTimeMillis() / 1000);
        try {
            String key = "trade:order_no:" + nowStr;
            // 1天后失效
            stringLongRedisTemplate.opsForValue().setIfAbsent(key, i, 5, TimeUnit.MINUTES);
            Long increment = stringLongRedisTemplate.opsForValue().increment(key, 1L);
            Assert.notNull(increment, "increment is null");
            long no = (increment - 1) % 1000000;
            noStr = String.format("%06d", no);
        } catch (Exception e) {
            noStr = String.format("%06d", i);
            log.error("获取订单号自增位异常，降级到随机数 {}", noStr, e);
        }
        return prefix + nowStr + noStr;
    }


}
